﻿using System;
using System.Collections.Generic;
using System.Data.Objects;
using System.Drawing;
using System.Drawing.Imaging;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using PhotgalleryEntities;
using PhotoGalleryEnteties;

namespace PhotogalleryModel
{
    public class PhotoRepository
    {
        
        
        
        
        
        public  PhotoRepository(ModelStorage storage ,ModelContext modelContext  )
        {
            _context = modelContext.Context ;
            _photoManager = storage.PhotoManager ;
        }

        private IContext _context;
        private IPhotoManager _photoManager;


       /// <summary>
       /// Method for instantiating new PhotoInfo
       /// </summary>   
       /// <returns></returns>
        public PhotoInfo CreatePhoto(Bitmap image )
       {
           
            PhotoInfo photo =_context.CreateObject<PhotoInfo>();
           photo.CreationDate = DateTime.Now;
           photo.Height = image.Height;
           photo.Width = image.Width;
           photo.Format = ParseImageFormat(image.RawFormat);
           return photo;
       }

        
        public void DeletePhoto(int photoId)
        {
            PhotoInfo photo = _context.Photos.Where(p => p.PhotoId == photoId).FirstOrDefault();
            if (photo == null)
                throw new GalleryModelException(string.Format("Photo with id {0} doesn`t exist", photoId));
            DeletePhoto(photo);
        }


        



        public void DeletePhoto(PhotoInfo photoInfo )
        {
            if (photoInfo == null)
                throw new ArgumentNullException();
            _context.DeleteObject(photoInfo);
        }

        /// <summary>
        /// Method for saving image specified in photoinfo in storage
        /// </summary>
        public void SetPhoto(PhotoInfo photoInfo ,Bitmap image)
        {
            _photoManager.SavePhoto(photoInfo, image);
        }
        
  
        public string ParseImageFormat(ImageFormat format)
        {
            
            PropertyInfo[] properties = typeof (ImageFormat).GetProperties( BindingFlags.Static |BindingFlags.Public  );
            
            foreach (PropertyInfo  property in properties )
            {
                if (property.GetValue( null,BindingFlags.Static ,null,null,null).Equals( format))
                {
                    return property.Name;
                }
            }

            throw new Exception("UnknownFileFormat");
        }

        public ImageFormat GetImageFormat(string formatName)
        {
            formatName = formatName.ToLower();
            PropertyInfo[] properties = typeof(ImageFormat).GetProperties(BindingFlags.Static | BindingFlags.Public);
            foreach (PropertyInfo  property in properties )
            {
                if (property.Name.ToLower() == formatName)
                    return (ImageFormat) property.GetValue(null, BindingFlags.Static, null, null, null);
            }

            throw new Exception("UnknownFileFormat");
        }

        #region SelectMethods

        public PhotoInfo GetPhotoInfo(int PhotoId)
        {
            PhotoInfo photo =_context.Photos.Where(p => p.PhotoId == PhotoId).FirstOrDefault( );
            if (photo == null)
                throw new GalleryModelException(string.Format("Photo with id {0} doesn`t exist", PhotoId));
            return photo;
        }

        public IQueryable<PhotoInfo > GetPhotoInfoForUser(string loweredUserName)
        {
            return _context.Photos.Where(p => p.Album.Owner.UserName.ToLower() == loweredUserName);
        }


        public IQueryable <PhotoInfo > GetPhotoInfoForAlbum(int AlbumId)
        {
            return _context.Photos.Where(p => p.Album.AlbumId == AlbumId);
        }

       
        //method for retrieving photos from photo storage
        public IStorageResult GetOriginalPhoto(PhotoInfo photoInfo)
        {
            return _photoManager.LoadOriginalPhoto(photoInfo);
        }

        public IStorageResult GetOptimizedPhoto(PhotoInfo photoInfo)
        {
            return _photoManager.LoadOptimizedPhoto(photoInfo);
        }
        public IStorageResult GetPhotoThumbnail(PhotoInfo photoInfo)
        {
            return _photoManager.LoadThumbnail(photoInfo);
        }

        
        public IEnumerable< PhotoInfo> GetRandomPhotos(int n)
        {
            if (n <= 0)
                throw new ArgumentException("Argument should be >0");
            return _context.GetRandomPhotos(n);
        }
        

        public IEnumerable <PhotoInfo > GetLastPhotos(int quantity)
        {
            return _context.Photos.OrderBy(p => p.CreationDate).Take(quantity);
        }
       



        #endregion





        /// <summary>
        /// Method for validating Photo in model
        /// </summary>
        /// <param name="photo"> photo to validate </param>
        /// <returns></returns>
        public ICollection< ValidationError> ValidatePhoto(PhotoInfo photo)
        {
            List<ValidationError> errorList = new List<ValidationError>();
            // validating title 
            if(photo.Title ==null)
            {
                errorList.Add(new ValidationError() {ErrorTag = "Title", ErrorMessage = "TitleRequired"});
            }

            //validating image extension
            if (!Enum.GetNames(typeof(AllowedImageFormats )).Contains(photo.Format, StringComparer.Create( CultureInfo.InvariantCulture ,true )))
            {
                errorList.Add(new ValidationError()
                                  {
                                      ErrorTag = "",
                                      ErrorMessage = string.Format("Unsupported file type. Supported are:{0}",
                                                                   string.Join(" ", Enum.GetNames(typeof (AllowedImageFormats ))))
                                  });
            }
           
            //property album shoul be set 
            if(photo.Album==null )
            {
                errorList.Add(new ValidationError() {ErrorTag = "Album", ErrorMessage = "Album hasn`t been set"});
            }

            //photo title should be unique in album 
            string[] photoNames = photo.Album.Photos.Where(p => p.Title == photo.Title).Select(p => p.Title).ToArray() ;
            if(photoNames .Length >1)
            {
                errorList.Add(new ValidationError()
                                  {
                                      ErrorTag = "",
                                      ErrorMessage =
                                          string.Format("Album {0} already has a photo with title {1} ", photo.Album.Title,
                                                        photo.Title)
                                  });
            }
            
            return errorList;
        }




        
    }
}
